/*日志读写缓冲区设计
*   通过读写指针控制
*   vector存储字符(非字符串)
*   对外提供：支持写入数据/获取可用数据首地址/获取可读数据长度/初始化缓冲区，重置读写位置/对buffer实现交换/判断缓冲区是否为空
*/

#ifndef _BUFFER_H_
#define _BUFFER_H_

#include <iostream>
#include <vector>
#include <cassert>

namespace Log
{
    //默认缓冲区大小为(10M字节) 测试用1M
    #define DEFAULT_BUF_SIZE (1*1024*1024)
    //缓冲区增长阈值(80M) 测试用8M
    #define THRESHOLD_BUF_SIZE (8*1024*1024)
    //缓冲区线性增长值(10M) 测试用1M
    #define LINEAR_BUF_SIZE (1*1024*1024)
    class Buffer
    {
    public:
        Buffer():_buffer(DEFAULT_BUF_SIZE),_read_pos(0),_write_pos(0) {}

        //写入数据
        void push(const char* data,size_t len)
        {
            //1.处理空间不足的情况
            if(len > writeAbleSize())
            {
                //返回写入失败(release版本启用)
                //return false;

                //这里默认扩容模式 让上层通过writeAbleSize决定是扩容还是阻塞
                //扩容(Debug性能测试)
                reserve(len);
            }
            //2.写入数据
            std::copy(data,data+len,&_buffer[_write_pos]);
            //3.更新写入下标
            moveWritePos(len);
        }

        //获取可用数据首地址
        const char* begin()
        {
            //可读数据必须存在
            assert(readAbleSize());
            return &_buffer[_read_pos];
        }

        //获取可读数据长度
        size_t readAbleSize()
        {
            return _write_pos - _read_pos;
        }

        //获取还能写入的数据大小
        size_t writeAbleSize()
        {
            //对于扩容模式来说 不存在可写空间大小这一说 因为总是可写的
            //该接口仅为固定大小缓冲区通过
            return _buffer.size() - _write_pos;
        }

        //修改读指针位置
        void moveReadPos(size_t len)
        {
            //指针偏移不能超过可读数据的长度
            assert(readAbleSize() >= len);
            //偏移
            _read_pos += len;
        }

        //初始化缓冲区，重置读写位置
        void reset()
        {
            _write_pos = _read_pos = 0;
        }

        //交换缓冲区
        void swap(Buffer& buf)
        {
            _buffer.swap(buf._buffer);
            std::swap(_write_pos,buf._write_pos);
            std::swap(_read_pos,buf._read_pos);
        }

        //判断缓冲区是否为空
        bool empty()
        {
            return _read_pos == _write_pos;
        }

    private:
        //修改写指针位置(内部接口 不允许外界访问)
        void moveWritePos(size_t len)
        {
            //写指针不能超过最大容量
            assert(len <= writeAbleSize());
            _write_pos += len;
        }

        //扩容
        void reserve(size_t len)
        {
            //空间足够就不扩容
            if(len <= writeAbleSize()) return;
            size_t now_size = 0;
            //防止扩容的空间小于len的情况
            while(now_size < len)
            {
                //检查是否可以翻倍增长(没有超过阈值)
                if(_buffer.size() < THRESHOLD_BUF_SIZE) now_size += _buffer.size()*2;
                //线性增长
                else now_size += _buffer.size() + LINEAR_BUF_SIZE;
            }

            //扩容
            _buffer.resize(now_size);
        }
    private:
        std::vector<char> _buffer;
        size_t _write_pos; //读指针 实际为下标
        size_t _read_pos; //写指针 - 实际为下标
    };
}

#endif